package com.enterprise.projectManager.service.implemention;

import com.enterprise.projectManager.model.Project;
import com.enterprise.projectManager.rope.ProjectRope;
import com.enterprise.projectManager.service.ProjectService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.*;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Transactional
@Slf4j
public class ProjectImpl implements ProjectService {
    private final ProjectRope projectRope;
    private final CountServiceImpl countImpl;
    @PersistenceContext
    private EntityManager em;

    @Override
    public Project create(Project project) {
        if (project.getProjectId() == null) project.setProjectId(countImpl.generalProjectId());
        return projectRope.save(project);
    }

    @Override
    public Boolean delete(String id) {
        Optional<Project> optionalProject = projectRope.findById(id);
        projectRope.delete(optionalProject.get());
        return Boolean.TRUE;    //待进一步判断
    }

    @Override
    public Project update(Project project) {
        return projectRope.save(project);
    }

    @Override
    public Project search(String id) {
        Optional<Project> optionalProject = projectRope.findById(id);
        return optionalProject.orElse(new Project()); // 或者根据实际需求返回其他默认值
    }

    @Override
    public List<JsonNode> list(int limit) {
        // 从数据库中检索前 limit 个项目
        List<Project> projects = projectRope.findAll(PageRequest.of(0, limit)).getContent();
        List<JsonNode> jsonNodeList = new ArrayList<>();
        projects.forEach(project -> {
            jsonNodeList.add(formatLog(project));
        });
        return jsonNodeList;
    }

    @Override
    public List<JsonNode> listAll() {
        List<Project> projects = projectRope.findAll();
        List<JsonNode> jsonNodeList = new ArrayList<>();
        projects.forEach(project -> {
            jsonNodeList.add(formatLog(project));
        });
        return jsonNodeList;
    }

    @Override
    public JsonNode formatLog(Project project) {
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode = objectMapper.valueToTree(project);
        Date now = new Date();
        if (now.after(project.getProjectPlanFinishtime()))
            ((ObjectNode) jsonNode).put("warning", 2);
        else if (now.before(project.getProjectPlanStarttime()))
            ((ObjectNode) jsonNode).put("warning", 0);
        else {
            Long t1 = ChronoUnit.DAYS.between(project.getProjectPlanStarttime().toLocalDate(), project.getProjectPlanFinishtime().toLocalDate());
            Long t2 = ChronoUnit.DAYS.between(LocalDate.now(), project.getProjectPlanFinishtime().toLocalDate());

            Double rate = Double.valueOf(t2) / Double.valueOf(t1);
            if (rate > 0.8) ((ObjectNode) jsonNode).put("warning", 0);
            else if (rate > 0.5) ((ObjectNode) jsonNode).put("warning", 1);
            else ((ObjectNode) jsonNode).put("warning", 2);
        }
        return jsonNode;
    }

    @Override
    public Boolean isExistId(String projectId) {
        if (projectRope.existsById(projectId)) return Boolean.TRUE;
        else return Boolean.FALSE;
    }

    @Override
    public List<String> getAllPlace() {
        return projectRope.findAllDistinctPlaces();
    }

    //获取传递参数的非空属性
    public Map<String, Object> getNonNullProperties(Project project) {
        Map<String, Object> result = new HashMap<>();
        Map<String, Object> nonNullProperties = Arrays.stream(Project.class.getDeclaredFields())
                .filter(field -> {
                    try {
                        field.setAccessible(true);
                        return field.get(project) != null;
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                        return false;
                    }
                })
                .collect(Collectors.toMap(Field::getName, field -> {
                    try {
                        return field.get(project);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                        return null;
                    }
                }));

        nonNullProperties.forEach((key, value) -> {
            if (value != null) {
                //不为空数组
                if (!(value instanceof List && ((List) value).isEmpty()))
                    result.put(key, value);
            }
        });
        return result;
    }

    //搜索符合条件的项目
    public List<Project> findProjectsByProperties(Map<String, Object> nonNullProperties) {
        // 创建 CriteriaBuilder 对象
        CriteriaBuilder cb = em.getCriteriaBuilder();
        // 创建 CriteriaQuery 对象
        CriteriaQuery<Project> cq = cb.createQuery(Project.class);
        // 创建 Root 对象
        Root<Project> root = cq.from(Project.class);
        // 创建 Predicate 数组
        List<Predicate> predicates = new ArrayList<>();
        // 遍历 Map 对象，根据不同的属性和值创建 Predicate 对象
        nonNullProperties.forEach((key, value) -> {
            // 如果值是一个 List 对象，使用 in 方法来创建 Predicate 对象
            if (value instanceof List) {
                predicates.add(root.get(key)
                        .in((List) value));
            } else if (value instanceof String) {
                predicates.add(cb.like(root.get(key)
                        , "%" + value + "%"));
            } else {
                predicates.add(cb.equal(root.get(key)
                        , value));
            }
        });
// 使用 and 方法将所有的 Predicate 连接起来，作为 where 条件
        cq.where(cb.and(predicates.toArray(new Predicate[0])));
// 创建 TypedQuery 对象
        TypedQuery<Project> query = em.createQuery(cq);
// 执行查询，得到结果列表
        List<Project> result = query.getResultList();
// 返回结果列表
        return result;
    }

    //格式化项目
    @Override
    public List<JsonNode> filterProject(Project project) {
        Map<String, Object> nonNullProperties = getNonNullProperties(project);
        List<Project> projects = findProjectsByProperties(nonNullProperties);
        List<JsonNode> jsonNodeList = new ArrayList<>();
        projects.forEach(p -> {
            jsonNodeList.add(formatLog(p));
        });
        return jsonNodeList;
    }

    @Override
    public Project findByProjectId(String id1) {
        Optional<Project> optionalProject = projectRope.findById(id1);
        return optionalProject.orElse(null); // 或者根据实际需求返回其他默认值
    }

    //导入数据
    @Override
    public String importProjects(List<Project> projects) {
        int repeatNum =0;
        for (Project project : projects)
        {
            if (project.getProjectId() == null)
            {
                project.setProjectId(countImpl.generalProjectId());
                projectRope.save(project);
            }
            else if (projectRope.existsById(project.getProjectId())) repeatNum++;
            else projectRope.save(project);
        }
        return "总共导入"+projects.size()+"条数据,"+"有"+repeatNum+"条数据重复;  "+"成功导入"+(projects.size()-repeatNum)+"条数据";
    }
    //将格式转换为Project
    public List<Project> formatJsonToProject(List<Map<String,String>> maps)
    {
        List<Project> projects =new ArrayList<>();
        maps.forEach(map->{
                    Project project = new Project(
                            map.get("项目编号").isEmpty() ? null : map.get("项目编号"),
                            map.get("项目名称").isEmpty() ? null : map.get("项目名称"),
                            map.get("项目所在地").isEmpty() ? null :map.get("项目所在地"),
                            map.get("项目金额").isEmpty() ? null : Double.valueOf(map.get("项目金额")),
                            null,
                            map.get("状态").isEmpty() ? null : map.get("状态"),
                            map.get("项目阶段").isEmpty() ? null : map.get("项目阶段"),
                            map.get("项目进度").isEmpty() ? null : Double.valueOf(map.get("项目进度")),
                            null,
                            null,
                            null,
                            null,
                            map.get("项目负责人").isEmpty() ? null : map.get("项目负责人"),
                            map.get("负责人联系电话").isEmpty() ? null : map.get("负责人联系电话"),
                            map.get("项目概况").isEmpty() ? null : map.get("项目概况"),
                            null,
                            null,
                            null,
                            null,
                            null
                    );
                    java.util.Date parsedDate1 = java.sql.Date.valueOf(map.get("计划开工时间"));
                    java.util.Date parsedDate2 = java.sql.Date.valueOf(map.get("计划完工时间"));
                    if (map.get("实际开工时间") != null) {
                        java.util.Date parsedDate3 = java.sql.Date.valueOf(map.get("实际开工时间"));
                        project.setProjectRealStarttime(new java.sql.Date(parsedDate3.getTime()));
                    }
                    if (map.get("实际完工时间") != null) {
                        java.util.Date parsedDate4 = java.sql.Date.valueOf(map.get("实际完工时间"));
                        project.setProjectRealFinishtime(new java.sql.Date(parsedDate4.getTime()));
                    }

                    project.setProjectPlanStarttime(new java.sql.Date(parsedDate1.getTime()));
                    project.setProjectPlanFinishtime(new java.sql.Date(parsedDate2.getTime()));

                    projects.add(project);
            System.out.println(project);
        });
        return projects;
    }
    //导入表格
    public String importExcel(List<Map<String,String>> maps)
    {
        return importProjects(formatJsonToProject(maps));
    }
}
